#ifndef BOARDBASE_H
#define BOARDBASE_H

#include "rte_data.h"
#include "plc_var.pb.h"
#include <pb_common.h>

#ifdef USE_ALARM
#include <Alarm.h>
#endif

#include <noise_flt.h>
#include <plc_task.h>
#include <rte_data.h>
#include "dbnc_flt.h"
#include <plc_iom.h>

#include "smodule.h"

#if IO_XA_NRS > 0

#include "in_analog.h"

#endif

#ifdef USE_LFS

#include "flashFs.h"

#endif

// #undef _GLIBCXX_USE_C99_STDINT_TR1
//
// #include <functional>

#ifdef ARDUINO_ARCH_STM32

#include "HardwareTimer.h"

#endif

#include "kSerial.h"
#include "mFirmata.h"
#include "plc_const.h"
#include "in_analog.h"

#ifdef USE_SPIFLASH

#include "SPIFlash.h"

#endif
#ifdef USE_QSPI

#include "QUAD_SPI.h"

#endif
using u8 = unsigned char;
using u16 = unsigned short;
using s16 = short;
using uint32_t = uint32_t;
using s32 = int32_t;
using byte = u8;
extern int VECTOR_ISR;
extern const char *hwModel;

//*
//* @brief 板硬件基类,抽象公共接口，具体实现由继承类实现
class boardBase : public iom {
public:
    // 选项
    u8 enOut = 1;
    // 选项
    u8 enInput = 1;

    int begin(uint32_t tick) override;

    int run(uint32_t tick) override;

    // 从定位符写到缓存变量
    void output(uint32_t tick);

    // #@endgroup
    // # @begingroup 编程操作接口

#ifdef ARDUINO


    //* @endgroup
    static int reset();

#endif

    static int clock_diag();

#ifdef __PLATFORMIO_BUILD_DEBUG__

    int dev_test(uint32_t tick) override;

#endif
#ifndef THIS_IS_BOOTLOADER

    // 恢复出厂设置，清除保持变量
    virtual void initReset();

    // 从缓存变量输出到硬件
    virtual void board_output(uint32_t tick) = 0;

    // 调试开关
    virtual int get_dbg_jmpr_get();

    // 复位开关
    virtual int get_rst_jmpr_get();

    // 写输出变量
    virtual void set_dout(u16 ch, u8 *pVoid);

    // 从输出变量读值
    virtual int get_dout(u16 ch, u8 *pVoid) const;

    // 从输入变量读值
    virtual int get_din(u16, u8 *pVoid) const;

    virtual u8 get_din(u16) const;

    virtual int get_ain(u8 ch, void *v_buf) const;

    virtual int get_aout(int inx, u16 *pVoid) const;

    virtual void set_aout(int i, const u16 *pVoid) const;

    static void outputPort(byte i, bool b);

    int diag(uint32_t tick) override;

#ifndef FIRMATA_DISABLE_REPORT

    virtual int readAnalogValue(mFirmata *fm, nStream *, uint64_t analogInputsToReport, byte);

#endif

    virtual int capability_query(mFirmata *fm, nStream *pStream);

    virtual int analog_mapping_query(mFirmata *fm, nStream *pStream);

    virtual int setPinState(mFirmata *fm, nStream *pStream, u8 pin, int value);

    // 清除存储
    virtual void flashClear();

    //* @startgroup 运行状态接口
    virtual void plc_run_start() = 0;

    virtual void plc_run_end() = 0;

    // 写输出变量
    virtual int set_output(u8, u8, u8, u8, byte *, u8);

    // 从变量读输入
    virtual int get_input(int, int, int, int, void *);

    int get_input(plc_loc_tbl_t) override;

    int set_output(plc_loc_tbl_t) override;

    u8 get_input_fast(u8, u8, u8, u8) override;

    void set_output_fast(u8, u8, u8, u8, u8) override;

#ifdef RTE_APP

    //* @group modbus通信接口
    virtual int modbus_cb_read(u16 start_addr, u16 word_count, u16 *data_words);

    virtual int modbus_cb_write(u16 start_addr, u16 word_count, u16 *data_words);

    virtual int modbus_cb_read_bits(u16 start_addr, u16 word_count, u8 *data_words);

    int modbus_cb_write_bit(u16 start_addr, u16 bit_count, u8 data_words);

    virtual int modbus_cb_write_bits(u16 start_addr, u16 word_count, u8 *data_words);

    static int modbus_read_serial(u16 start_addr, u16 word_count, u16 *data_words, kSerial *serial, u16 start, u16 len);

    virtual mem_block *get_retain();

#endif

    const char *name() override {
        return "board";
    }

#endif

    // 定义保持设备

    static int modbus_read_pin(u16 start_addr, u16 word_count, u16 *data_words, u16 start, u16 len);

    static int modbus_read_analog_value(u16 start_addr, u16 word_count, u16 *data_words, u16 start, u16 len);

    static int modbus_write_pin(u16 start_addr, u16 word_count, u16 *data_words, u16 start, u16 len);

    static int modbus_write_analog_value(u16 start_addr, u16 word_count, u16 *data_words, u16 start, u16 len);

    int modbus_read_di(u16 start_addr, u16 word_count, u8 *data_words, u16 start, u16 len) const;

    int modbus_read_do(u16 start_addr, u16 word_count, u8 *data_words, u16 start, u16 len) const;

    int modbus_write_do(u16 start_addr, u16 word_count, const u8 *data_words, u16 start, u16 len);
    //* @endgroup

public:
    uint32_t poll_tick{};
    static const u8 xport[IO_XI_NRS];
    static const u8 yport[IO_YO_NRS];
#ifdef FORWARD_NRS
    static nStream *forwardStream[FORWARD_NRS];
#endif

    uint32_t lfs_file_crc32(const char *name);

#if IO_XA_NRS > 0

    class in_analog<unsigned short> _ina[IO_XA_NRS];

#endif

    virtual void led_run(int) = 0;

    virtual void led_err(int) = 0;

    virtual void led_pwr(int);

    [[noreturn]] static void goto_iap();

#ifdef USE_LFS
#ifndef LFS_READONLY

    static int write_file(const char *file, const char *buf, int len);

    virtual int remove_file(const char *file);

#endif
#endif


    int flash_bootloader_from_lfs();

    virtual void led(uint32_t tick);

    int lfs2ram(const char *name, u8 *start);

    int usb_to_dataFlash(const char *name, uint32_t flash_start_addr, uint32_t header_size);

    int usb_copy_to_lfs(const char *name);

    int lfs_to_Flash(const char *name, uint32_t flash_start_addr, uint32_t block_start, uint32_t block_nrs);

#ifdef USE_FLASH_LFS_MV

    int lfs_to_progFlash(const char *name, uint32_t flash_start_addr, uint32_t header_size);

#endif

#ifdef FORWARD_NRS

    void forwardMessage(char port, uint8_t c);

#endif
    uint32_t err_led_tick;
#ifdef USE_DATA_FLASH
    SPIFlash *dataFlash;
#endif
#ifdef USE_QSPI
    QUAD_SPI progFlash;
#endif

    static int copy_file_lfs2sd(const char *src, const char *dst);

    static int cp_sd2lfs(const char *src, const char *dst);

    int write_file_to_sd(const char *file, const char *buf, int len);

    static void write_file_thread(void *p);

    static void copy_file_lfs2sd_thread(void *arg);

    static int sd_read_file(const char *file, char *buf, int len);

    static int read_file(const char *file, char *buf, int len);

    pb_state last_state;

    int copy_usb_flash(const char *name, uint32_t start, uint32_t blk_start, uint32_t blk_nrs);

    in_analog<u16> bvbat, bvref, btemp;

    bool load_holdValued;
    pb_board_info data;

    int setInfoValue(u8 inx, u8 size, byte *val);

    int getInfoValue(int inx, void *pVoid, int size);

    bool x[IO_XI_NRS]{};
    bool y[IO_YO_NRS]{};
    int32_t xa[IO_XA_NRS]{};
    int32_t ya[IO_YA_NRS]{};
    pb_cpu cpu;
    pb_firmata firmata;
    int32_t xi_sel[IO_XI_NRS]{};
    int32_t yo_sel[IO_YO_NRS]{}; //
    int32_t xa_sel[IO_XA_NRS]{}; //
    int32_t ya_sel[IO_YA_NRS]{}; //
};

extern "C"
{
void net_led_on();
void net_led_off();
int lfs2ram(const char *name, u8 *start);
}

extern "C" u16 crc_16(u8 *buf, int cnt, u16 init);

extern "C" const uint32_t crc32_table[256];
#ifdef ARDUINO_ARCH_STM32
extern USART_TypeDef *msg_uart;
#endif
#endif
